/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Portions created by the Initial Developer are
 * Copyright (C) 2012 the Initial Developer.
 * All Rights Reserved.
 *
 * The Original Code is "http://semi-frame.googlecode.com/svn/trenk/".
 *
 * The Initial Developer of the Original Code is the author below.
 */
/**
 * @file LogPrinter.cpp
 * @brief auto generated.
 * @author morningcloud
 * @date 2011/03/11
 */

#include "semi/logg/LogPrinter.h"

namespace semi {
namespace logg {

LogPrinter::LogPrinter() {
}

//void LogPrinter::setLogSize(int size) {
//    log_size = size;
//}

void LogPrinter::init(std::string path, int size) {

    //    memset(file_path, 0x00, sizeof(file_path));
    //    strcpy(file_path, path.c_str());
    //    std::string name = util::StringUtil::replace(path, "/", "");
    //    if (256 < name.length())
    //        name = name.substr(path.length() - 255, path.length());

    this->file_path = path;
    this->semaphore.init(path);
    this->log_size = size;
}

LogPrinter::~LogPrinter() {
    //    this->semaphore.postAll();
}

void LogPrinter::logging(const char *pFormat, ...) {

    // ��¾����
    this->semaphore.wait();

    // ������å�
    va_list list; // ���Ѱ���ꥹ��
    va_start( list, pFormat );

    this->print(this->file_path, this->log_size, pFormat, list);

    va_end( list );

    // ��¾����
    this->semaphore.post();
    this->semaphore.close();
    return;
}

void LogPrinter::print(std::string file_path, int file_size, const char *pFormat,
        va_list list) {

    // create date string
    struct timeval val;

    gettimeofday(&val, NULL);

    char time_str[64] = { 0 };
    struct tm *date = localtime(&val.tv_sec);
    sprintf(time_str, "%04d-%02d-%02d %02d:%02d %02d.%03d ", date->tm_year
            + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour,
            date->tm_min, date->tm_sec, val.tv_usec / 1000);

    // std::cout << time_str << std::endl;

    printf(time_str);
    vprintf(pFormat, list);

    // for file
    FILE *fp;
    if ((fp = fopen(file_path.c_str(), "a")) == NULL) {
        std::stringstream ss;
        ss << "LogPrinter::print fopen " << file_path;
        perror(ss.str().c_str());
        return;
    }
    // file size
    struct stat statbuf;
    if (stat(file_path.c_str(), &statbuf) < 0) { // present log size
        std::stringstream ss;
        ss << "LogPrinter::print stat " << file_path;
        perror(ss.str().c_str());
        if (EOF == fclose(fp))
            perror("LogPrinter::print fclose error");
        return;
    }

    // buck up
    //    std::cout << "        LogPrinter::print st_size:" << statbuf.st_size
    //            << " < " << file_size << std::endl;
    if (statbuf.st_size > file_size) {

        fclose(fp);

        char tmp[64] = { 0 };
        sprintf(tmp, "_%02d-%02d_%02d-%02d_%02d", date->tm_mon + 1,
                date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec);
        std::string cpy = file_path + std::string(tmp);

        // if it exists buck up.
        if (access(cpy.c_str(), F_OK) == 0) {
            remove(cpy.c_str());
        }
        // back up
        rename(file_path.c_str(), cpy.c_str());

        // open new file
        if ((fp = fopen(file_path.c_str(), "a")) == NULL) {
            std::stringstream ss;
            ss << "LogPrinter::print fopen new file " << cpy;
            perror(ss.str().c_str());
            return;
        }
    }

    // date out put
    if ((fprintf(fp, "%s", time_str)) <= 0) {
        std::stringstream ss;
        ss << "LogPrinter::print fprintf " << file_path;
        perror(ss.str().c_str());
    }

    // args out put
    else if ((vfprintf(fp, pFormat, list)) <= 0) {
        std::stringstream ss;
        ss << "LogPrinter::print vfprintf " << file_path;
        perror(ss.str().c_str());
    }

    if (EOF == fclose(fp)) {
        perror("LogPrinter::print fclose error");
    }

    return;
}

void LogPrinter::terminate() {

    std::cout << "    LogPrinter::terminate " << this->file_path << std::endl;
    this->semaphore.terminate();
}

}

}
